package com.xtpt.disaster.common.DM;

import com.xtpt.disaster.bean.DbnodeInfo;
import com.xtpt.disaster.common.ClientCmdBuilder;
import com.xtpt.disaster.common.PropertyConfig;
import com.xtpt.disaster.common.consts.DBEnum;
import com.xtpt.disaster.common.consts.DataTypeEnum;
import com.xtpt.disaster.common.consts.OSTypeEenum;
import com.xtpt.disaster.utils.ServerPathUtil;
import org.codehaus.plexus.util.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class DMCmdBuilder extends ClientCmdBuilder {

    @Autowired
    ServerPathUtil pathUtil;

    /**
     * 客户端操作系统类型
     */
    private OSTypeEenum osType;
    /**
     * 启动或停止达梦服务命令格式(默认Linux)
     */
    private String serviceCmdFormat="service %2$s %1$s";;
    /**
     * 客户端节点信息
     */
    private DbnodeInfo clientDBNodeInfo;
    /**
     * 构造函数
     * @throws Exception 异常
     */
    public DMCmdBuilder(){
        super();
    }

    public DMCmdBuilder setOSType(OSTypeEenum osType) throws Exception
    {
        this.osType = osType;
        super.setOSType(this.osType);
        switch (this.osType)
        {
            case LINUX:
                serviceCmdFormat="service %2$s %1$s";
                break;
            case WINDOWS:
                serviceCmdFormat="net %1$s %2$s";
                break;
        }
        return this;
    }

    /**
     * 设置客户端节点信息
     * @param nodeInfo 客户端节点
     * @return this
     * @throws Exception
     */
    public DMCmdBuilder initializeWithClientNode(DbnodeInfo nodeInfo) throws Exception {
        //设置客户端则初始化父类
        super.init();
        this.clientDBNodeInfo=nodeInfo;
        return this.setOSType(OSTypeEenum.getObject(nodeInfo.getNodeOsType()));
    }
    /**
     * 启动达梦数据库服务
     * @return this
     */
    public DMCmdBuilder StartService()
    {
        AddCmdWithNewGroupLn(String.format(serviceCmdFormat, "start",clientDBNodeInfo.getNodeDbServiceName()));
        return this;
    }

    /**
     * 停止达梦数据库服务
     * @return this
     */
    public DMCmdBuilder StopService()
    {
        AddCmdWithNewGroupLn(String.format(serviceCmdFormat, "stop",clientDBNodeInfo.getNodeDbServiceName()));
        return this;
    }

    public DMCmdBuilder ChownDbPathLinux() {
        if (osType == OSTypeEenum.LINUX) {
            AddCmdWithNewGroupLn(
                    String.format("chown -R %s %s",
                            clientDBNodeInfo.getNodeDbOwner(),
                            clientDBNodeInfo.getNodeDbDatabasePath()
                    )
            );
        }
        return this;
    }

    /**
     * 数据库备份
     * @param taskId
     * @param backFileName
     * @param FullOrIncrement
     * @param disc
     * @return
     * @throws Exception
     */
    public Map<String,String> dbBackUp(String taskId, String backFileName, String FullOrIncrement, String disc,String backFlag) throws Exception {
        Map<String,String> pathMap = new HashMap<>();
        String fullFileName = backFileName+super.getBackFileExtend();
        String serverFilePath=pathUtil.getServerFilePathDM(taskId,
                fullFileName,
                DataTypeEnum.DATABASE,
                DBEnum.DAMENG,
                FullOrIncrement);

        String exePath=combinePath(clientDBNodeInfo.getNodeDbBinPath(),"disql");
        String conn=String.format("%s %s/%s@%s:%s",
                exePath.replace(" ",super.getBlankSpaceReplace()),
                clientDBNodeInfo.getNodeDbUsername(),
                clientDBNodeInfo.getNodeDbPassword(),
                clientDBNodeInfo.getNodeIp(),
                clientDBNodeInfo.getNodeDbPort());

        String inc;
        String template="BACKUP DATABASE %1$s %2$s TO %7$s BAKFILE '%4$s%3$s%5$s' backupinfo '%6$s';";
        if(FullOrIncrement.equalsIgnoreCase("FULL"))
        {
            inc="";
        }
        else if(FullOrIncrement.equalsIgnoreCase("INCREMENT"))
        {
            inc= String.format("WITH BACKUPDIR '%s'", clientDBNodeInfo.getNodeDbBackupPath());
        }
        else
        {
            throw new Exception("未选择增量或全量备份类型");
        }
        //sql为DM数据库的备份命令
        String sql=String.format(template,
                FullOrIncrement,
                inc,
                backFileName,
                clientDBNodeInfo.getNodeDbBackupPath(),
                super.getBackFileExtend(),
                disc,
                "jobId"+backFlag);

        String clientFilePath = clientDBNodeInfo.getNodeDbBackupPath()+fullFileName;
        // 实际数据库备份流程，通过conn语句在客户端上连接数据库，然后执行备份指令sql，备份完成后退出，最后使用scp或者pscp命令传输备份文件到服务器上。
        AddCmdWithNewGroupLn(conn).AddCmdLn(sql).AddCmdLn("exit;");
        TransactionFilesToServer(clientFilePath, serverFilePath);
        pathMap.put(serverFilePath,clientFilePath);
        return pathMap;
    }

    /**
     * 数据库恢复
     * @param mainRestoreFilePathOnClient
     * @param allBackupFiles
     * @return
     */
    public DMCmdBuilder dbRestore(String mainRestoreFilePathOnClient, List<String> allBackupFiles) {

        String template="%sdmrestore INI_PATH=%s FILE=%s DUMMY=Y";
        TransactionFilesToClient(allBackupFiles,clientDBNodeInfo.getNodeDbBackupPath());
        String cmd= String.format(template,
                clientDBNodeInfo.getNodeDbBinPath().replace(" ",super.getBlankSpaceReplace()),
                clientDBNodeInfo.getNodeDbIniPath().replace(" ",super.getBlankSpaceReplace())
                ,mainRestoreFilePathOnClient.replace(" ",super.getBlankSpaceReplace()));

        StopService().AddCmdWithNewGroupLn(cmd).ChownDbPathLinux().StartService();
        return this;
    }

//////////////////////////////////////////////////// 如下重写父类方法
    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public DMCmdBuilder AddCmdLn(String cmd)
    {
        super.AddCmdLn(cmd);
        return this;
    }

    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public DMCmdBuilder AddCmd(String cmd)
    {
        super.AddCmd(cmd);
        return this;
    }
    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public DMCmdBuilder AddCmdWithNewGroupLn(String cmd)
    {
        super.AddCmdWithNewGroupLn(cmd);
        return this;
    }

    /**
     * 新添加命令组并将命令加入到新组（自动加回车符）
     * @param cmd 命令字符串
     * @return this
     */
    public DMCmdBuilder AddCmdWithNewGroup(String cmd)
    {
        super.AddCmdWithNewGroup(cmd);
        return this;
    }

}
